package com.smh.demo1.a33;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.*;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;

import java.util.Arrays;
import java.util.Set;

/**
 * @author shiminghui
 * @date 2025/5/6 20:36
 * @description: TODO
 */
@Configuration
public class A33_3 {
    public static void main(String[] args) throws Exception {

        SpringApplication springApplication = new SpringApplication(A33_3.class);
        // 这个不会覆盖掉启动类的解析,因为一个是sources对象,一个是primarySources
        springApplication.setSources(Set.of("classpath:Bean1.xml"));

        springApplication.addInitializers(applicationContext -> {
            if (applicationContext instanceof GenericApplicationContext gac) {
                gac.registerBean("bean2", Bean2.class);
            }
        });

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 2. 封装启动 args");
        DefaultApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 8. 创建容器");
        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);


        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 9. 准备容器");
        // 即执行 initializers方法
        Set<ApplicationContextInitializer<?>> initializers = springApplication.getInitializers();
        for (ApplicationContextInitializer initializer : initializers) {
            initializer.initialize(context);
        }

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 10. 加载 bean 定义");
        // 就是加载之前的bean定义的源
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(beanFactory);
        Set<String> sources = springApplication.getSources();
        for (String source : sources) { // 这里是因为只有xml配置文件,所以才这样写, 一般需要判断是否支持xml
            xmlReader.loadBeanDefinitions(source);
        }
        AnnotatedBeanDefinitionReader annoReader = new AnnotatedBeanDefinitionReader(beanFactory); // 处理由注解定义的Bean
        annoReader.register(A33_3.class); // 处理当前类,让其处理ServletWebServerFactory
        ClassPathBeanDefinitionScanner classReader = new ClassPathBeanDefinitionScanner(beanFactory); // 处理由类路径扫描定义的Bean(即处理ComponentScan注解)


        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 11. refresh 容器");
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println("name:" + name + " 来源：" + beanFactory.getBeanDefinition(name).getResourceDescription());
        }

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>> 12. 执行 runner");
        for (CommandLineRunner commandLineRunner : context.getBeansOfType(CommandLineRunner.class).values()) {
            commandLineRunner.run(args);
        }

        for (ApplicationRunner applicationRunner : context.getBeansOfType(ApplicationRunner.class).values()) {
            applicationRunner.run(applicationArguments);
        }


        context.close();

    }

    public static GenericApplicationContext createApplicationContext(WebApplicationType webApplicationType) {
        return switch (webApplicationType) {
            case SERVLET -> new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE -> new AnnotationConfigReactiveWebServerApplicationContext();
            case NONE -> new AnnotationConfigApplicationContext();
        };
    }

    @Bean
    public TomcatServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public CommandLineRunner commandLineRunner() {
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                System.out.println("commandLineRunner.run()  " + Arrays.toString(args));
            }
        };
    }

    @Bean
    public ApplicationRunner applicationRunner() {
        return new ApplicationRunner() {
            @Override
            public void run(ApplicationArguments args) throws Exception {
                System.out.println("applicationRunner.run()  " + Arrays.toString(args.getSourceArgs()));
                for (String optionName : args.getOptionNames()) {
                    System.out.println(optionName + ":" + args.getOptionValues(optionName));
                }
                System.out.println("--------");
                for (String nonOptionArgs : args.getNonOptionArgs()) {
                    System.out.println(nonOptionArgs);
                }
            }
        };
    }
}
